/* The Doctor's Office Simulation for project 1 */

#include "system.h"
#include "synch.h"
#include "list.h"
#include <iostream>
#include <string>
using namespace std;

#ifndef PRO1
#define PRO1

// Constant values
#define MAX_NUM_DOCTORS 3
#define MAX_NUM_NURSES 5
#define MAX_NUM_XTECH 2
#define MAX_NUM_IMAGE 3
#define MAX_NUM_ROOMS 5

// The state of staff in the office
enum StaffState {
	AVAILABLE, UNAVAILABLE, noExist
};

// Possible symptoms
enum Symptom {
	PAIN, NAUSEA, ALIEN_VOICIES
};

// Possible Xray results
enum XrayResult {
	NOTHING, BREAK, COMPOUND_FRACTURE
};

// Waiting room nurse action
enum WRNAction {
	GIVE_FORM, ACCEPT_FORM, GIVE_SHEET, NO_ACTION
};

// The state of patient
enum PatientState {
	NEED_EXAMINE, FINE, NEED_XRAY, NEED_SHOT, XRAY_DONE, DONE
};

// Children action
enum ChildAction {
	FOLLOW, LEAVE, XRAY, SHOT
};

// Examine Room State
enum RoomState {
	NOT_USE, IN_USE, NOT_EXIST
};

// The structure of examination sheet
typedef struct SheetEntry {
	int id;
	int doctorId;
	int examineRoomId;
	Symptom patientSymptom;
	PatientState state;
	int imageNum;
	XrayResult xrayResults[MAX_NUM_IMAGE];
} SheetEntry;

int test;

// Global variables are declared in the following
Symptom possibleSymptons[3];
XrayResult possibleXrayResult[3];

// Variables for the exam sheets
List *wrnList;
// There will be only one sheet in the wall pocket outside each exam room
SheetEntry *wallPocket[MAX_NUM_ROOMS];	

// Variables for the examine rooms
RoomState examineRoom[MAX_NUM_ROOMS];
Lock *wallPocketLock;
Lock *examineRoomPatientLock[MAX_NUM_ROOMS];
Condition *examineRoomPatientCV[MAX_NUM_ROOMS];
int doctorInRoom[MAX_NUM_ROOMS];

// Lock and Condition variable that ensure Office staff are set up early to the patients
Lock *initialLock;
Condition *initialCV;
int startSign = 0;
int totalPatientNum;

// Variables for waiting room nurse
WRNAction wrnAction;
StaffState wrnState;
int patientIdWithWRN;
int patientAge;
int wrnLineNum = 0;
int nurseIdWithWRN;
Lock *wrnLock;
Condition *wrnCV;
Lock *wrnLineLock;
Condition *wrnLineCV;

// Variables for doctors
SheetEntry *sheetForDoctor[MAX_NUM_DOCTORS];
StaffState doctorState[MAX_NUM_DOCTORS];
Lock *doctorLock[MAX_NUM_DOCTORS];
Condition *doctorCV[MAX_NUM_DOCTORS];
int doctorGoRoomId[MAX_NUM_DOCTORS];

// Variables for patients
Lock **patientLock;
Condition **patientCV;
int *roomId;
int *xtIdWithPatient;
PatientState *patientneedto;
Symptom *symptomResponse;
int *patientWithNurse;

// Variables for children
Lock **childLock;
Condition **childCV;
ChildAction *childAction;
int childNum = 0;

// Variables for cashier
StaffState cashierState;
int cashierLineNum;
int patientIdWithCashier;
Lock *cashierLock;
Condition *cashierCV;
Lock *cashierLineLock;
Condition *cashierLineCV;
SheetEntry *sheetForCashier;

// Variables for Xray technician
int xtImageNum[MAX_NUM_XTECH];
StaffState xtechnicianstate[MAX_NUM_XTECH];
Condition *xRayCV[MAX_NUM_XTECH];
Lock *xRayLock[MAX_NUM_XTECH];
Lock *xRayWaitLineLock[MAX_NUM_XTECH];
Condition *xRayWaitLineCV[MAX_NUM_XTECH];
int xRayWaitLineNum[MAX_NUM_XTECH];
Lock *waitListLock[MAX_NUM_XTECH];
List *xrayWaitList[MAX_NUM_XTECH];
Lock *finishListLock;
List *xrayFinishList;
int xRayTechNum;

// Variables for Nurse
SheetEntry *sheetForNurse[MAX_NUM_NURSES];
int patientWaitNum = 0;	// The number of patients waiting for nurse to call them
Lock *nurseXtechLock;
Lock *nurseDoctorLock;
int nurseWrnCount = 0;
Condition *nurseWrnLineCV;
Lock *cabinetLock;	// The lock for using the cabinet
int totalNurseNum = 0;

// Functions
// Take rand time to do tasks
void doTask() {
	int i;
	int time = rand()%20+10;
	for (i=0; i<time; i++) {
		currentThread->Yield();
	}
}

// Patient gets form from waiting room nurse
void GetForm(int index) {
	wrnLineLock->Acquire();	// Acquire the lock
	if (wrnState == UNAVAILABLE) {
		// There are some one before me
		// Increase the number in the line, and wait for my turn
		wrnLineNum ++;
		if(test==2 || test==7)
		printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to get registration form.\n", index);
		wrnLineCV->Wait(wrnLineLock);
	}else {
		wrnState = UNAVAILABLE;
	}
	wrnLock->Acquire();
	wrnLineLock->Release();
	// Now there is nobody in line. Waiting room nurse is available
	// Talk to her directly
	wrnAction = GIVE_FORM;	// Get the form
	patientIdWithWRN = index;
	wrnCV->Signal(wrnLock);	// Wake up the waiting room nurse
	wrnCV->Wait(wrnLock);	// Wait for the form
	// Get the form, go to fill the form
	if(test==2 || test==7)
	printf("Adult patient [%d] get the form from the Waiting Room Nurse.\n", index);
	wrnCV->Signal(wrnLock);	// Signal the waiting room nurse that I am leaving to fill the form
	wrnLock->Release();	// Release the lock and go somewhere
}

// Patient submits form to waiting room nurse
void SubmitForm(int index) {
	wrnLineLock->Acquire();	// Acquire the lock
	if (wrnState == UNAVAILABLE) {
		// There are some one before me
		// Increase the number in the line, and wait for my turn
		wrnLineNum ++;
		if(test==2 || test==7)
		printf("Adult Patient [%d] gets in line of the Waiting Room Nurse to submit registration form.\n", index);
		wrnLineCV->Wait(wrnLineLock);
	}else {
		wrnState = UNAVAILABLE;
	}
	wrnLock->Acquire();
	wrnLineLock->Release();
	// Now there is nobody in line. Waiting room nurse is available
	// Talk to her directly
	wrnAction = ACCEPT_FORM;	// Submit the form
	patientIdWithWRN = index;
	patientAge = 18+rand()%62;
	if(test==2 || test==7)
	printf("Adult patient [%d] submit the filled form to the Waiting Room Nurse.\n", index);
	wrnCV->Signal(wrnLock);	// Wake up the waiting room nurse
	wrnCV->Wait(wrnLock);	// Wait for the examination sheet
	// Get the sheet, wait for the nurse
	wrnCV->Signal(wrnLock);	// Signal the waiting room nurse that I am leaving to wait the nurse
	patientLock[index]->Acquire();	// Make patient wait for nurse first
	wrnLock->Release();	// Release the lock and wait for the nurse
	patientCV[index]->Wait(patientLock[index]);
}

void GoToExamineRoom(int index) {
	// Follow the nurse
	int myRoomId = roomId[index];
	if(test==2 || test==7 || test==1 || test==4 || test==5)
	printf("Adult Patient [%d] is following Nurse [%d] to Examination Room [%d].\n", index, patientWithNurse[index], myRoomId);
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	if(test==2 || test==7 || test==1 || test==4 || test==5)
	printf("Adult Patient [%d] has arrived at Examination Room [%d].\n", index, myRoomId);
	// Get into the examine room and interact with nurse
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	symptomResponse[index] = possibleSymptons[rand()%3];
	switch (symptomResponse[index]) {
		case PAIN:
			if(test == 7)
			printf("Adult Patient [%d] says, “My symptoms are Pain”.\n", index);
			break;
		case NAUSEA:
			if(test == 7)
			printf("Adult Patient [%d] says, “My symptoms are Nausea”.\n", index);
			break;
		case ALIEN_VOICIES:
			if(test == 7)
			printf("Adult Patient [%d] says, “My symptoms are Hear Alien Voices”.\n", index);
			break;
		default:
			break;
	}
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	// Wait for the doctor
	// Make sure the patient will wait for the doctor first
	examineRoomPatientLock[myRoomId]->Acquire();
	patientCV[index]->Signal(patientLock[index]);
	patientLock[index]->Release();
	// Patient wait for the doctor
	examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
}

void BackToExamineRoom(int index) {
	// Follow the nurse
	// Make sure the patient will wait for the doctor first
	examineRoomPatientLock[roomId[index]]->Acquire();
	patientCV[index]->Signal(patientLock[index]);
	patientLock[index]->Release();
	// Patient wait for the doctor
	examineRoomPatientCV[roomId[index]]->Wait(examineRoomPatientLock[roomId[index]]);
}

void GetShot(int index) {
	// Patient is told she need a shot
	int myRoomId = roomId[index];
	examineRoomPatientLock[myRoomId]->Release();
	patientLock[index]->Acquire();
	// Wait nurse to get the medicine
	if(test == 7)
	printf("Adult Patient [%d] says, \"Yes I am ready for the shot\".\n", index);
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	// The shot is done
	patientCV[index]->Signal(patientLock[index]);
	examineRoomPatientLock[myRoomId]->Acquire();
	patientLock[index]->Release();
	// Wait the nurse to take me to the cashier
	examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
}

// Patient interacts with Xray technician
void takexRay(int index){
	if(test == 7 || test==4||test==5)
	printf("Adult Patient [%d] waits for a Nurse to escort them to Xray room.\n", index);
	examineRoomPatientCV[roomId[index]]->Signal(examineRoomPatientLock[roomId[index]]);
	patientLock[index]->Acquire();
	examineRoomPatientLock[roomId[index]]->Release();
	patientCV[index]->Wait(patientLock[index]);
	//Patient goes to the waiting room of xray room
	int roomNum = xtIdWithPatient[index];
	xRayWaitLineLock[roomNum]->Acquire();
	patientCV[index]->Signal(patientLock[index]);
	patientLock[index]->Release();
	if (xtechnicianstate[roomNum] == UNAVAILABLE){
		//there are someone in front of the patient,he has to wait 
		xRayWaitLineNum[roomNum]++;
		xRayWaitLineCV[roomNum]->Wait(xRayWaitLineLock[roomNum]);
	}
	else {
		xtechnicianstate[roomNum] = UNAVAILABLE;
	}
	xRayWaitLineLock[roomNum]->Release();
	xRayLock[roomNum]->Acquire();
	xRayCV[roomNum]->Signal(xRayLock[roomNum]);
	xRayCV[roomNum]->Wait(xRayLock[roomNum]);
	if(test==7)
	printf("Adult Patient [%d] gets on the table.\n", index);
	xRayCV[roomNum]->Signal(xRayLock[roomNum]);
	if(test==7)
	printf("Adult Patient [%d] has been asked to take an Xray.\n", index);
	int imageNum = xtImageNum[roomNum];
	for (int i=0; i<imageNum-1; i++){
		xRayCV[roomNum]->Wait(xRayLock[roomNum]);
		xRayCV[roomNum]->Signal(xRayLock[roomNum]);
	}
	xRayCV[roomNum]->Wait(xRayLock[roomNum]);
	xRayCV[roomNum]->Signal(xRayLock[roomNum]);
	patientLock[index]->Acquire();
	xRayLock[roomNum]->Release();
	//patient wait in the finish xray waiting room  
	patientCV[index]->Wait(patientLock[index]); 
}

// Patient interacts with doctor
void InteractWithDoctor(int index){
	int myRoomId = roomId[index];
	int doctorId = doctorInRoom[myRoomId];
	doctorLock[doctorId]->Acquire();
	examineRoomPatientLock[myRoomId]->Release();
	doctorCV[doctorId]->Signal(doctorLock[doctorId]);
	doctorCV[doctorId]->Wait(doctorLock[doctorId]);
	if(test==7||test==6)
	printf("Adult Patient [%d] has been diagnosed by Doctor [%d].\n", index, doctorId);
	if (patientneedto[index] == NEED_XRAY){
		if(test==7||test==6)
	   printf("Adult Patient [%d] has been informed by Doctor [%d] that he needs an Xray.\n", index, doctorId);
	}
	if (patientneedto[index] == NEED_SHOT){
		if(test==7||test==6)
	   printf("Adult Patient [%d] has been informed by Doctor [%d] that he will be administered a shot.\n", index, doctorId);
	}
	doctorCV[doctorId]->Signal(doctorLock[doctorId]);
	examineRoomPatientLock[myRoomId]->Acquire();
	doctorLock[doctorId]->Release();
	examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
}

// Patient pays money to the cashier
void PayMoney(int index) {
	examineRoomPatientLock[roomId[index]]->Release();
	cashierLineLock->Acquire();
	if (cashierState != AVAILABLE) {
		// The cashier is not available wait in the line
		cashierLineNum ++;
		if(test==3||test==7)
			printf("Adult Patient [%d] enters the queue for Cashier\n", index);
		cashierLineCV->Wait(cashierLineLock);
	}else {
		cashierState = UNAVAILABLE;
	}

	cashierLock->Acquire();
	cashierLineLock->Release();
	// If the cashier is available, walk to the cashier
	patientIdWithCashier = index;
	if(test==3||test==7){
		printf("Adult Patient [%d] reaches the Cashier.\n", index);
		printf("Adult Patient [%d] hands over his examination sheet to the Cashier.\n", index);
	}
	// Wait cashier determine the fee
	cashierCV->Signal(cashierLock);
	cashierCV->Wait(cashierLock);
	if(test==3||test==7)
		printf("Adult Patient [%d] pays the Cashier $.... \n", index);
	// Wait for the receipt
	cashierCV->Signal(cashierLock);
	cashierCV->Wait(cashierLock);
	if(test==3||test==7)
		printf("Adult Patient [%d] receives a receipt from the Cashier.\n", index);
	cashierCV->Signal(cashierLock);
	if(test==3||test==7||test==5)
		printf("Adult Patient [%d] leaves the doctor's office.\n", index);
	totalPatientNum --;
	cashierLock->Release();
}

// Adult patient
void AdultPatient(int index) {
	initialLock->Acquire();
	while (startSign != 0) {
		// Check the start signal to see if I can start
		initialCV->Wait(initialLock);
	}
	initialLock->Release();
	srand(time(0));
	// A patient gets into the office
	printf("Adult Patient [%d] has entered the Doctor's Office Waiting Room.\n", index);
	// First, he has to interact with the waiting room nurse to get a form
	GetForm(index);
	// The patient fills the form
	doTask();
	// He comes back to the waiting room nurse to submit the form
	SubmitForm(index);
	// The patient is waiting for the nurse to call him
	GoToExamineRoom(index);
	InteractWithDoctor(index);
	while (1) {
		PatientState patientaction = patientneedto[index];
		if (patientaction == NEED_XRAY){
			takexRay(index);
		}
		else if (patientaction == NEED_SHOT){
			GetShot(index);
		}
		else if (patientaction == XRAY_DONE) {
			BackToExamineRoom(index);
			InteractWithDoctor(index);
		}
		else if (patientaction == DONE){
			break;
		}
	}	
	PayMoney(index);
}

// Child patient
void ChildPatient(int index) {
	while (1) {
		childLock[index]->Acquire();
		childCV[index]->Wait(childLock[index]);
		// Wait for parent telling them to follow
		if (childAction[index] == FOLLOW) {
			if(test==1 || test==4||test==7)
				printf("Parent[%d] asks Child Patient[%d] to follow them.\n", index, index);
			childCV[index]->Signal(childLock[index]);
		}else if (childAction[index] == LEAVE) {
			childCV[index]->Signal(childLock[index]);
			childLock[index]->Release();
			break;
		}
		childLock[index]->Release();
	}
}

// Parent
void Parent(int index) {
	initialLock->Acquire();
	while (startSign != 0) {
		// Check the start signal to see if I can start
		initialCV->Wait(initialLock);
	}
	initialLock->Release();
	
	//Parent gets form ---------
	printf("Child Patient [%d] has entered the Doctor's Office Waiting Room with Parent [%d].\n", index, index);
	wrnLineLock->Acquire();	// Acquire the lock
	if (wrnLineNum != 0 || wrnState == UNAVAILABLE) {
		// There are some one before me
		// Increase the number in the line, and wait for my turn
		wrnLineNum ++;
		if(test==2||test==7)
		printf("Parent[%d] gets in line of the Waiting Room Nurse to get registration form.\n", index);
		wrnLineCV->Wait(wrnLineLock);
	}else {
		wrnState = UNAVAILABLE;
	}
	wrnLock->Acquire();
	wrnLineLock->Release();
	// Now there is nobody in line. Waiting room nurse is available
	// Talk to her directly
	wrnAction = GIVE_FORM;	// Get the form
	patientIdWithWRN = index;
	wrnCV->Signal(wrnLock);	// Wake up the waiting room nurse
	wrnCV->Wait(wrnLock);	// Wait for the form
	if(test==2||test==7)
	printf("Parent of child patient[%d] gets the form from the Waiting Room Nurse.\n", index);
	wrnCV->Signal(wrnLock);	// Signal the waiting room nurse that I am leaving to fill the form
	wrnLock->Release();	// Release the lock and go somewhere
	
	doTask();
	//Parent submits form---------
	wrnLineLock->Acquire();	// Acquire the lock
	if (wrnLineNum != 0 ||wrnState == UNAVAILABLE) {
		// There are some one before me
		// Increase the number in the line, and wait for my turn
		wrnLineNum ++;
		if(test==2||test==7)
		printf("Parent[%d] gets in line of the Waiting Room Nurse to submit registration form.\n", index);
		wrnLineCV->Wait(wrnLineLock);
	}else {
		wrnState = UNAVAILABLE;
	}
	wrnLock->Acquire();
	wrnLineLock->Release();
	// Now there is nobody in line. Waiting room nurse is available
	// Talk to her directly
	wrnAction = ACCEPT_FORM;	// Submit the form
	patientIdWithWRN = index;
	patientAge = 1+rand()%18;
	if(test==2||test==7)
	printf("Parent of child patient[%d] submits the filled form to the Waiting Room Nurse.\n", index);
	wrnCV->Signal(wrnLock);	// Wake up the waiting room nurse
	wrnCV->Wait(wrnLock);	// Wait for the examination sheet
	// Get the sheet, wait for the nurse

	wrnCV->Signal(wrnLock);	// Signal the waiting room nurse that I am leaving to wait the nurse
	patientLock[index]->Acquire();	// Make patient wait for nurse first
	wrnLock->Release();	// Release the lock and wait for the nurse
	if(test==1||test==2||test==7||test==4)
	printf("Parent [%d] waits for a Nurse to escort them to the Xray room.\n", index);
	patientCV[index]->Wait(patientLock[index]);
	
	//Parent and child patients go to Examing room---------
	childAction[index] = FOLLOW;
	childLock[index]->Acquire();
	childCV[index]->Signal(childLock[index]);
	childCV[index]->Wait(childLock[index]);
	childLock[index]->Release();
	// Follow the nurse
	int myRoomId = roomId[index];
	if(test==1||test==4||test==7||test==2)
	printf("Parent[%d] is following Nurse[%d] to Examination Room[%d].\n", index, patientWithNurse[index], myRoomId);
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	if(test==1||test==4||test==7||test==2)
	printf("Parent[%d] has arrived at Examination Room [%d].\n", index, myRoomId);
	// Get into the examine room and interact with nurse
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	symptomResponse[index] = possibleSymptons[rand()%3];
	switch (symptomResponse[index]) {
		case PAIN:
			if(test==1||test==7)
			printf("Parent [%d] says, \"His symptoms are Pain\".\n", index);
			break;
		case NAUSEA:
			if(test==1||test==7)
			printf("Parent [%d] says, \"His symptoms are Nausea\".\n", index);
			break;
		case ALIEN_VOICIES:
			if(test==1||test==7)
			printf("Parent [%d] says, \"His symptoms are Hear Alien Voices\".\n", index);
			break;
		default:
			break;
	}
	patientCV[index]->Signal(patientLock[index]);
	patientCV[index]->Wait(patientLock[index]);
	// Wait for the doctor
	// Make sure the patient will wait for the doctor first
	examineRoomPatientLock[myRoomId]->Acquire();
	patientCV[index]->Signal(patientLock[index]);
	patientLock[index]->Release();
	// Patient wait for the doctor
	examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
	
	//interact with doctor----------
	myRoomId = roomId[index];
	int doctorId = doctorInRoom[myRoomId];
	doctorLock[doctorId]->Acquire();
	examineRoomPatientLock[myRoomId]->Release();
	doctorCV[doctorId]->Signal(doctorLock[doctorId]);
	doctorCV[doctorId]->Wait(doctorLock[doctorId]);
	if(test==7||test==6)
	printf("Child Patient [%d] has been diagnosed by Doctor [%d].\n", index, doctorId);
	if (patientneedto[index] == NEED_XRAY){
		if(test==7||test==6)
	   printf("Child Patient [%d] has been informed by Doctor [%d] that he needs an Xray.\n", index, doctorId);
	}
	if (patientneedto[index] == NEED_SHOT){
		if(test==7||test==6)
	   printf("Child Patient [%d] has been informed by Doctor [%d] that he will be administered a shot.\n", index, doctorId);
	}
	doctorCV[doctorId]->Signal(doctorLock[doctorId]);
	examineRoomPatientLock[myRoomId]->Acquire();
	doctorLock[doctorId]->Release();
	examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
	
	while (1) {
		PatientState patientaction = patientneedto[index];
		if (patientaction == NEED_XRAY){
			//takexRay(index);
			if(test==1||test==7||test==4)
				printf("Parent[%d] waits for a Nurse to escort them to the Xray room.\n", index);
			examineRoomPatientCV[roomId[index]]->Signal(examineRoomPatientLock[roomId[index]]);
			childAction[index] = FOLLOW;
			childLock[index]->Acquire();
			childCV[index]->Signal(childLock[index]);
			childCV[index]->Wait(childLock[index]);
			childLock[index]->Release();
			patientLock[index]->Acquire();
			examineRoomPatientLock[roomId[index]]->Release();
			patientCV[index]->Wait(patientLock[index]);
			//Patient goes to the waiting room of xray room
			int roomNum = xtIdWithPatient[index];
			// Wait for Xray technician's instruction
			xRayWaitLineLock[roomNum]->Acquire();
			patientCV[index]->Signal(patientLock[index]);
			patientLock[index]->Release();
			if (xtechnicianstate[roomNum] == UNAVAILABLE){
				//there are someone in front of the patient,he has to wait 
				xRayWaitLineNum[roomNum]++;
				xRayWaitLineCV[roomNum]->Wait(xRayWaitLineLock[roomNum]);
			}
			else {
				xtechnicianstate[roomNum] = UNAVAILABLE;
			}
			xRayWaitLineLock[roomNum]->Release();
			xRayLock[roomNum]->Acquire();
			xRayCV[roomNum]->Signal(xRayLock[roomNum]);
			xRayCV[roomNum]->Wait(xRayLock[roomNum]);
			if(test==7)
				printf("Child Patient [%d] gets on the table.\n", index);
			xRayCV[roomNum]->Signal(xRayLock[roomNum]);
			if(test==7)
				printf("Child Patient [%d] has been asked to take an Xray.\n", index);
			int imageNum = xtImageNum[roomNum];
			for (int i=0; i<imageNum-1; i++){
				xRayCV[roomNum]->Wait(xRayLock[roomNum]);
				if(test==7)
					printf("Child Patienht [%d] moves for the next Xray.\n", index);
				xRayCV[roomNum]->Signal(xRayLock[roomNum]);
			}
			xRayCV[roomNum]->Wait(xRayLock[roomNum]);
			xRayCV[roomNum]->Signal(xRayLock[roomNum]);
			patientLock[index]->Acquire();
			xRayLock[roomNum]->Release();
			//patient wait in the finish xray waiting room  
			patientCV[index]->Wait(patientLock[index]); 
		}
		else if (patientaction == NEED_SHOT){
			// Patient is told she need a shot
			myRoomId = roomId[index];
			examineRoomPatientLock[myRoomId]->Release();
			patientLock[index]->Acquire();
			// Wait nurse to get the medicine
			if(test==1||test==7)
				printf("Parent [%d] says, \"Yes He is ready for the shot\".\n", index);
			patientCV[index]->Signal(patientLock[index]);
			patientCV[index]->Wait(patientLock[index]);
			// The shot is done
			if(test==7)
			printf("Child patient [%d] has been given a shot.\n", index);
			patientCV[index]->Signal(patientLock[index]);
			examineRoomPatientLock[myRoomId]->Acquire();
			patientLock[index]->Release();
			// Wait the nurse to take me to the cashier
			examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
		}
		else if (patientaction == XRAY_DONE) {
			//BackToExamineRoom(index);
			// Make sure the patient will wait for the doctor first
			childAction[index] = FOLLOW;
			childLock[index]->Acquire();
			childCV[index]->Signal(childLock[index]);
			childCV[index]->Wait(childLock[index]);
			childLock[index]->Release();
			patientCV[index]->Signal(patientLock[index]);
			patientCV[index]->Wait(patientLock[index]);
			examineRoomPatientLock[roomId[index]]->Acquire();
			patientCV[index]->Signal(patientLock[index]);
			patientLock[index]->Release();
			// Patient wait for the doctor
			examineRoomPatientCV[roomId[index]]->Wait(examineRoomPatientLock[roomId[index]]);
			//interact with doctor----------
			myRoomId = roomId[index];
			doctorId = doctorInRoom[myRoomId];
			doctorLock[doctorId]->Acquire();
			examineRoomPatientLock[myRoomId]->Release();
			doctorCV[doctorId]->Signal(doctorLock[doctorId]);
			doctorCV[doctorId]->Wait(doctorLock[doctorId]);
			if(test==7||test==6)
			printf("Child Patient [%d] has been diagnosed by Doctor [%d].\n", index, doctorId);
			if (patientneedto[index] == NEED_XRAY){
				if(test==7||test==6)
				printf("Child Patient [%d] has been informed by Doctor [%d] that he needs an Xray.\n", index, doctorId);
			}
			if (patientneedto[index] == NEED_SHOT){
				if(test==7||test==6)
				printf("Child Patient [%d] has been informed by Doctor [%d] that he will be administered a shot.\n", index, doctorId);
			}
			doctorCV[doctorId]->Signal(doctorLock[doctorId]);
			examineRoomPatientLock[myRoomId]->Acquire();
			doctorLock[doctorId]->Release();
			examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
		}
		else if (patientaction == DONE){
			break;
		}
	}	
	//PayMoney(index);
	childAction[index] = FOLLOW;
	childLock[index]->Acquire();
	childCV[index]->Signal(childLock[index]);
	childCV[index]->Wait(childLock[index]);
	childLock[index]->Release();
	examineRoomPatientCV[roomId[index]]->Signal(examineRoomPatientLock[roomId[index]]);
	examineRoomPatientCV[myRoomId]->Wait(examineRoomPatientLock[myRoomId]);
	
	examineRoomPatientLock[roomId[index]]->Release();
	cashierLineLock->Acquire();
	if (cashierState != AVAILABLE) {
		// The cashier is not available wait in the line
		cashierLineNum ++;
		if(test==1||test==7||test==3||test==4)
		printf("Parent[%d] enters the queue for Cashier.\n", index);
		cashierLineCV->Wait(cashierLineLock);
	}else {
		cashierState = UNAVAILABLE;
	}

	cashierLock->Acquire();
	cashierLineLock->Release();
	// If the cashier is available, walk to the cashier
	patientIdWithCashier = index;
	if(test==7||test==3){
		printf("Parent [%d] reaches the Cashier.\n", index);
		printf("Parent [%d] hands over his examination sheet to the Cashier.\n", index);
	}
	// Wait cashier determine the fee
	cashierCV->Signal(cashierLock);
	cashierCV->Wait(cashierLock);
	if(test==7||test==3)
	printf("Parent [%d] pays the Cashier $.... \n", index);
	// Wait for the receipt
	cashierCV->Signal(cashierLock);
	cashierCV->Wait(cashierLock);
	if(test==7||test==3)
	printf("Parent [%d] receives a receipt for Child Patient[%d] from the Cashier.\n", index, index);
	cashierCV->Signal(cashierLock);
	if(test==1||test==7||test==3||test==5)
	printf("Parent [%d] leaves the doctor's office with Child Patient[%d].\n", index, index);
	cashierLock->Release();
	totalPatientNum --;
}

// Only one waiting room nurse
void WaitingRoomNurse(int index) {
	// Make sure the thread is executed before patient threads
	initialLock->Acquire();
	startSign --;
	initialCV->Broadcast(initialLock);
	int nurseId;
	int patientId;
	while (1) {
		wrnLineLock->Acquire();
		// Check if there are nurses waiting
		if (nurseWrnCount == 0 && wrnLineNum == 0) {
			// No nurse, No patient
			wrnState = AVAILABLE;
		}else if (nurseWrnCount > 0) {
			// Nurse waiting and there are patients waiting for the nurse
			// Wake up the nurse
			nurseWrnLineCV->Signal(wrnLineLock);
			nurseWrnCount --;
			wrnState = UNAVAILABLE;
		}else if (wrnLineNum > 0) {
			wrnLineCV->Signal(wrnLineLock);
			wrnLineNum --;	// Decrease the number of patients in the line
			wrnState = UNAVAILABLE;
		}
		wrnLock->Acquire();
		initialLock->Release();
		wrnLineLock->Release();
		wrnCV->Wait(wrnLock);	// Wait for someone coming
		// Patient comes
		switch (wrnAction) {
			case GIVE_FORM:
				patientId = patientIdWithWRN;
				if (patientId < childNum){
					if(test==7||test==2)
						printf("Waiting Room nurse gives a form to the Parent of Child patient [%d].\n", patientId);
				}
				else{
					if(test==7||test==2)
						printf("Waiting Room nurse gives a form to Adult patient [%d].\n", patientId);
				}
				wrnCV->Signal(wrnLock);
				wrnCV->Wait(wrnLock);
				wrnLock->Release();
				break;
			case ACCEPT_FORM:
				patientId = patientIdWithWRN;
				if (patientId < childNum){
					if(test==7||test==2)
						printf("Waiting Room nurse accepts the form from Parent with name [%d] and age [%d].\n", patientId, patientAge);
				}
				else{
					if(test==7||test==2)
						printf("Waiting Room nurse accepts the form from Adult Patient with name [%d] and age [%d].\n", patientId, patientAge);			  	
				}
				SheetEntry *newSheet = new SheetEntry;
				newSheet->id = patientId;
				newSheet->state = NEED_EXAMINE;
				wrnList->Append(newSheet);
				if (patientId < childNum){
					if(test==7||test==2)
						printf("Waiting Room nurse creates an examination sheet for Child patient with name [%d] and age [%d].\n", patientId, patientAge);
				}
				else{
					if(test==7||test==2)
						printf("Waiting Room nurse creates an examination sheet for Adult patient with name [%d] and age [%d].\n", patientId, patientAge);			  	
				}
				if (patientId < childNum){
					if(test==1||test==7||test==2)
						printf("Waiting Room nurse tells the Parent [%d] to wait in the waiting room for a nurse.\n", patientId);
				}
				else{
					if(test==7||test==2)
						printf("Waiting Room nurse tells the Adult Patient [%d] to wait in the waiting room for a nurse.\n", patientId);			  	
				}
				patientWaitNum ++;
				wrnCV->Signal(wrnLock);
				wrnCV->Wait(wrnLock);
				wrnLock->Release();
				break;
			case GIVE_SHEET:
				nurseId = nurseIdWithWRN;
				sheetForNurse[nurseId] = (SheetEntry *) wrnList->Remove();
				if(test==7||test==2)
					printf("Waiting Room nurse gives examination sheet of patient[%d] to Nurse[%d].\n", sheetForNurse[nurseId]->id, nurseId);
				wrnCV->Signal(wrnLock);
				// Wait the nurse to take patient away
				wrnCV->Wait(wrnLock);
				wrnLock->Release();
				break;
			case NO_ACTION:
				break;
			default:
				printf("Error: Unkown states in WaitingRoomNurse\n");
				return;
		}
	}
}

// Find a available examine room
int FindExamineRoom() {
	wallPocketLock->Acquire();
	int found = -1;
	for (int i=0; i<MAX_NUM_NURSES; i++) {
		if (examineRoom[i] == NOT_USE) {
			examineRoom[i] = IN_USE;	// Occupy the room
			found = i;
			break;
		}
	}
	wallPocketLock->Release();
	return found;
}

// Release an examine room
void ReleaseExamineRoom(int index) {
	wallPocketLock->Acquire();
	if (examineRoom[index] != NOT_EXIST) {
		examineRoom[index] = NOT_USE;
	}else {
		printf("Error: examine room %d doesn't exist\n", index);
	}
	wallPocketLock->Release();
}

// Find an available doctor
int FindAvailableDoctor() {
	int doctorId = -1;
	nurseDoctorLock->Acquire();
	for (int i=0; i<MAX_NUM_DOCTORS; i++) {
		if (doctorState[i] == AVAILABLE) {
			doctorId = i;
			doctorState[i] = UNAVAILABLE;
			break;
		}
	}
	nurseDoctorLock->Release();
	return doctorId;
}

// Call a doctor
void CallDoctor(int index, int examineRoomId, SheetEntry *myLocalSheet) {
	// Find an available doctor
	int doctorId = FindAvailableDoctor();
	if (doctorId >= 0) {
		// There is an available doctor
		doctorLock[doctorId]->Acquire();
		// Tell the doctor which room to go
		doctorGoRoomId[doctorId] = examineRoomId;
		// Wake up the doctor
		doctorCV[doctorId]->Signal(doctorLock[doctorId]);
		if (myLocalSheet->id < childNum){
			if(test==1||test==7||test==6)
				printf("Nurse [%d] informs Doctor [%d] that Child Patient [%d] is waiting in the examination room [%d].\n", index, doctorId, myLocalSheet->id, examineRoomId);
		}
		else{
			if(test==7||test==6)
				printf("Nurse [%d] informs Doctor [%d] that Adult Patient [%d] is waiting in the examination room [%d].\n", index, doctorId, myLocalSheet->id, examineRoomId);
		}
		// Give doctor the examine sheet
		myLocalSheet->doctorId = doctorId;
		sheetForDoctor[doctorId] = myLocalSheet;
		if (myLocalSheet->id < childNum){
			if(test==7||test==6)
				printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Child Patient [%d].\n", index, doctorId, myLocalSheet->id);
		}
		else{
			if(test==7||test==6)
				printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult Patient [%d].\n", index, doctorId, myLocalSheet->id);	  	
		}
		doctorLock[doctorId]->Release();
	}else {
		// No doctor available, put the sheet in the wall pocket
		wallPocketLock->Acquire();
		wallPocket[examineRoomId] = myLocalSheet;
		wallPocketLock->Release();
	}
}

// Nurse
void Nurse(int index) {
	// Make sure the thread is executed before patient threads
	initialLock->Acquire();
	startSign --;
	initialCV->Broadcast(initialLock);
	initialLock->Release();
	SheetEntry *myLocalSheet;
	int xtechId;
	while (totalPatientNum > 0) {
		int examineRoomId = FindExamineRoom();
		if (examineRoomId >= 0) {
			// If there is an open examination room
			// Task 1: Get patient from waiting room, escort to exam room
			// Nurse will ask waiting room nurse whether there is any patient waiting for examination
			wrnLineLock->Acquire();
			if (wrnState == UNAVAILABLE) {
				nurseWrnCount ++;
				nurseWrnLineCV->Wait(wrnLineLock);
			}else {
				wrnState = UNAVAILABLE;
			}
			if (patientWaitNum > 0) {
				// There are some patients waiting for examination
				// Waiting room nurse gives the examination sheet to the nurse
				patientWaitNum --;
				wrnLock->Acquire();
				wrnLineLock->Release();
				// Tell the waiting room nurse to give a sheet
				if(test==7||test==2)
					printf("Nurse[%d] tells Waiting Room Nurse to give a new examination sheet.\n", index);
				nurseIdWithWRN = index;
				wrnAction = GIVE_SHEET;
				wrnCV->Signal(wrnLock);
				// Wait for the sheet
				wrnCV->Wait(wrnLock);
				myLocalSheet = sheetForNurse[index];
				wrnCV->Signal(wrnLock);
				patientLock[myLocalSheet->id]->Acquire();
				wrnLock->Release();
				// Nurse calls the patient to follow her
				roomId[myLocalSheet->id] = examineRoomId;
				patientWithNurse[myLocalSheet->id] = index;
				patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
				patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
				// Nurse takes the patient to the examination room
				if (myLocalSheet->id < childNum){
					if(test==7||test==1||test==4)
						printf("Nurse [%d] escorts Parent [%d] to the examination room [%d].\n", index, myLocalSheet->id, examineRoomId);
				}
				else{
					if(test==7||test==4)
						printf("Nurse [%d] escorts Adult Patient [%d] to the examination room [%d].\n", index, myLocalSheet->id, examineRoomId);
				}
				patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
				patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
				// Take temperature, blood pressure
				if (myLocalSheet->id < childNum){
					if(test==7){
						printf("Nurse [%d] takes the temperature and blood pressure of Child [%d].\n", index, myLocalSheet->id);
						// Ask sympton
						printf("Nurse [%d] asks Parent [%d] \"What Symptoms do you have?\"\n", index, myLocalSheet->id);
					}
				}
				else{
					if(test==7){
						printf("Nurse [%d] takes the temperature and blood pressure of Adult Patient [%d].\n", index, myLocalSheet->id);
						// Ask sympton
						printf("Nurse [%d] asks Adult Patient [%d] \"What Symptoms do you have?\"\n", index, myLocalSheet->id);
					}
				}
				patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
				// Wait for patient's response;
				patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
				// Write the sympton on the examine sheet
				myLocalSheet->patientSymptom = symptomResponse[myLocalSheet->id];
				if (myLocalSheet->id < childNum){
					if(test==7)
						printf("Nurse [%d] writes all the information of Child [%d] in his examination sheet.\n", index, myLocalSheet->id);
				}
				else{
					if(test==7)
						printf("Nurse [%d] writes all the information of Adult Patient [%d] in his examination sheet.\n", index, myLocalSheet->id);			  	
				}
				patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
				patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
				patientLock[myLocalSheet->id]->Release();
				// Call the doctor
				CallDoctor(index, examineRoomId, myLocalSheet);
			}else {
				wrnLock->Acquire();
				wrnLineLock->Release();
				wrnAction = NO_ACTION;
				wrnCV->Signal(wrnLock);
				wrnLock->Release();
				ReleaseExamineRoom(examineRoomId);
			}
		}
		doTask();
		// Task 2: Escort patient back to exam room
		finishListLock->Acquire();
		if (!xrayFinishList->IsEmpty()) {
			myLocalSheet = (SheetEntry *)xrayFinishList->Remove();
			myLocalSheet->state = XRAY_DONE;
			finishListLock->Release();
			patientLock[myLocalSheet->id]->Acquire();
			// Tell patient back to the examine room
			patientneedto[myLocalSheet->id] = XRAY_DONE;
			//YJ add
			examineRoomId = roomId[myLocalSheet->id];
			if (myLocalSheet->id < childNum){
				patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
				patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
				if(test==7||test==1||test==4)
					printf("Nurse [%d] escorts Parent [%d] to the examination room [%d].\n", index, myLocalSheet->id, examineRoomId);
			}
			else{
				if(test==7||test==4)
					printf("Nurse [%d] escorts Adult Patient [%d] to the examination room [%d].\n", index, myLocalSheet->id, examineRoomId);		  	
			}
			patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
			patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
			patientLock[myLocalSheet->id]->Release();
			// Call the doctor
			int doctorId = myLocalSheet->doctorId;
			nurseDoctorLock->Acquire();
			if (doctorState[doctorId] == AVAILABLE) {
				doctorState[doctorId] = UNAVAILABLE;
			}else {
				doctorId = -1;
			}
			nurseDoctorLock->Release();
			if (doctorId >=0) {
				// The doctor is available
				doctorLock[doctorId]->Acquire();
				// Tell the doctor which room to go
				doctorGoRoomId[doctorId] = myLocalSheet->examineRoomId;
				// Wake up the doctor
				doctorCV[doctorId]->Signal(doctorLock[doctorId]);
				if (myLocalSheet->id < childNum){
					if(test==7||test==6)
					printf("Nurse [%d] informs Doctor [%d] that Child Patient [%d] is waiting in the examination room [%d].\n", index, doctorId, myLocalSheet->id, myLocalSheet->examineRoomId);
				}
				else{
					if(test==7||test==6)
					printf("Nurse [%d] informs Doctor [%d] that Adult Patient [%d] is waiting in the examination room [%d].\n", index, doctorId, myLocalSheet->id, myLocalSheet->examineRoomId);			  	
				}
				// Give doctor the examine sheet
				myLocalSheet->doctorId = doctorId;
				sheetForDoctor[doctorId] = myLocalSheet;
				if (myLocalSheet->id < childNum){
					if(test==7||test==6)
					printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Child Patient [%d].\n", index, doctorId, myLocalSheet->id);
				}
				else{
					if(test==7||test==6)
					printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult Patient [%d].\n", index, doctorId, myLocalSheet->id);			  	
				}
				doctorLock[doctorId]->Release();
			}else {
				// The doctor is not available, put the sheet in the wall pocket
				wallPocketLock->Acquire();
				wallPocket[examineRoomId] = myLocalSheet;
				wallPocketLock->Release();
			}
		}else {
			finishListLock->Release();
		}
		doTask();
		// Task 3: Check wall pocket outside the room
		examineRoomId = -1;
		wallPocketLock->Acquire();
		for (int i=0; i<MAX_NUM_ROOMS; i++) {
			if (wallPocket[i] != NULL) {
				examineRoomId = i;
				myLocalSheet = wallPocket[i];
				wallPocket[i] = NULL;
				break;
			}
		}
		wallPocketLock->Release();
		if (examineRoomId >=0 ) {
			// There is an examine sheet in the wall pocket
			if(test==7||test==4)
			printf("Nurse [%d] checks the wall box of examination room[%d]\n", index, examineRoomId);
			// Take different actions according to the patient's state in the examination room
			switch (myLocalSheet->state) {
				case NEED_XRAY:
					// Tell patient to follow to take xray
					patientneedto[myLocalSheet->id] = NEED_XRAY;
					examineRoomPatientLock[examineRoomId]->Acquire();
					examineRoomPatientCV[examineRoomId]->Signal(examineRoomPatientLock[examineRoomId]);
					examineRoomPatientCV[examineRoomId]->Wait(examineRoomPatientLock[examineRoomId]);
					examineRoomPatientLock[examineRoomId]->Release();
					patientLock[myLocalSheet->id]->Acquire();
					xtechId = rand()%xRayTechNum;
					// Wait the patient
					// Take patient to the Xray Technician
					if (myLocalSheet->id < childNum){
						if(test==7||test==1||test==4)
						printf("Nurse [%d] escorts Parent [%d] to the X-ray room [%d]\n", index, myLocalSheet->id, xtechId);
					}
					else{
						if(test==7||test==4)
						printf("Nurse [%d] escorts Adult Patient [%d] to the X-ray room [%d]\n", index, myLocalSheet->id, xtechId);				  	
					}
					// Put the examination sheet in the pocket
					myLocalSheet->examineRoomId = examineRoomId;
					waitListLock[xtechId]->Acquire();
					if (myLocalSheet->id < childNum){
						if(test==7)
							printf("Nurse [%d] informs X-Ray Technician [%d] about Child Patient [%d] and hands over the examination sheet.\n", index, myLocalSheet->id, xtechId);
					}
					else{
						if(test==7)
							printf("Nurse [%d] informs X-Ray Technician [%d] about Adult Patient [%d] and hands over the examination sheet.\n", index, myLocalSheet->id, xtechId);						
					}
					xrayWaitList[xtechId]->Append(myLocalSheet);
					xtIdWithPatient[myLocalSheet->id] = xtechId;
					patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
					patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
					if(test==7)
						printf("Nurse [%d] leaves the X-ray waiting Room.\n", index);
					patientLock[myLocalSheet->id]->Release();
					waitListLock[xtechId]->Release();
					break;
				case XRAY_DONE:
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
						printf("Nurse [%d] gets examination sheet for Parent [%d] in Xray waiting room.", index, myLocalSheet->id);
					}
					else{
						if(test==7)
						printf("Nurse [%d] gets examination sheet for Adult Patient [%d] in Xray waiting room.", index, myLocalSheet->id);
					}
					int doctorId = myLocalSheet->doctorId;
					nurseDoctorLock->Acquire();
					if (doctorState[doctorId] == AVAILABLE) {
						doctorState[doctorId] = UNAVAILABLE;
					}else {
						doctorId = -1;
					}
					nurseDoctorLock->Release();
					if (doctorId >=0) {
						// The doctor is available
						doctorLock[doctorId]->Acquire();
						// Tell the doctor which room to go
						doctorGoRoomId[doctorId] = examineRoomId;
						// Wake up the doctor
						doctorCV[doctorId]->Signal(doctorLock[doctorId]);
						if (myLocalSheet->id < childNum){
							if(test==7||test==6)
							printf("Nurse [%d] informs Doctor [%d] that Child Patient [%d] is waiting in the examination room [%d].\n", index, doctorId, myLocalSheet->id, examineRoomId);
						}
						else{
							if(test==7||test==6)
							printf("Nurse [%d] informs Doctor [%d] that Adult Patient [%d] is waiting in the examination room [%d].\n", index, doctorId, myLocalSheet->id, examineRoomId);					  	
						}
						// Give doctor the examine sheet
						myLocalSheet->doctorId = doctorId;
						sheetForDoctor[doctorId] = myLocalSheet;
						if (myLocalSheet->id < childNum){
							if(test==7||test==6)
							printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Child Patient [%d].\n", index, doctorId, myLocalSheet->id);
						}
						else{
							if(test==7||test==6)
							printf("Nurse [%d] hands over to the Doctor [%d] the examination sheet of Adult Patient [%d].\n", index, doctorId, myLocalSheet->id);					  	
						}
						doctorLock[doctorId]->Release();
					}else {
						// The doctor is not available, put the sheet in the wall pocket
						wallPocketLock->Acquire();
						wallPocket[examineRoomId] = myLocalSheet;
						wallPocketLock->Release();
					}
					break;
				case NEED_EXAMINE:
					// Need Doctor
					CallDoctor(index, examineRoomId, myLocalSheet);
					break;
				case NEED_SHOT:
					examineRoomPatientLock[examineRoomId]->Acquire();
					// Wake up the patient
					examineRoomPatientCV[examineRoomId]->Signal(examineRoomPatientLock[examineRoomId]);
					patientLock[myLocalSheet->id]->Acquire();
					patientneedto[myLocalSheet->id] = NEED_SHOT;
					examineRoomPatientLock[examineRoomId]->Release();
					// Get medicine
					cabinetLock->Acquire();
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
							printf("Nurse [%d] goes to supply cabinet to give to take medicine for Parent [%d].\n", index, myLocalSheet->id);
					}
					else{
						if(test==7)
							printf("Nurse [%d] goes to supply cabinet to give to take medicine for Adult Patient [%d].\n", index, myLocalSheet->id);				  	
					}
					cabinetLock->Release();
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
							printf("Nurse [%d] asks Parent [%d] \"Whether you are ready for the shot?\"\n", index, myLocalSheet->id);
					}
					else{
						if(test==7)
							printf("Nurse [%d] asks Adult Patient [%d] \"Whether you are ready for the shot?\"\n", index, myLocalSheet->id);				  	
					}
					patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
					// Shot
					// Shot over
					if (myLocalSheet->id < childNum){
						if(test==7||test==1)
						printf("Nurse [%d] tells Parent [%d] \"Shot is over.\"\n", index, myLocalSheet->id);
					}
					else{
						if(test==7)
						printf("Nurse [%d] tells Adult Patient [%d] \"Shot is over.\"\n", index, myLocalSheet->id);				  	
					}
					myLocalSheet->state = DONE;
					patientCV[myLocalSheet->id]->Signal(patientLock[myLocalSheet->id]);
					patientCV[myLocalSheet->id]->Wait(patientLock[myLocalSheet->id]);
					patientLock[myLocalSheet->id]->Release();
				case FINE:
				case DONE:
					examineRoomPatientLock[examineRoomId]->Acquire();
					// Tell patient to follow
					patientneedto[myLocalSheet->id] = DONE;
					// Take the patient to the cashier
					if (myLocalSheet->id < childNum){
						examineRoomPatientCV[examineRoomId]->Signal(examineRoomPatientLock[examineRoomId]);
						examineRoomPatientCV[examineRoomId]->Wait(examineRoomPatientLock[examineRoomId]);
						if(test==7||test==4||test==1)
							printf("Nurse [%d] escorts Parent [%d] to Cashier.\n", index, myLocalSheet->id);
					}
					else{
						if(test==7||test==4)
							printf("Nurse [%d] escorts Adult Patient [%d] to Cashier.\n", index, myLocalSheet->id);
					}
					examineRoomPatientCV[examineRoomId]->Signal(examineRoomPatientLock[examineRoomId]);
					examineRoomPatientLock[examineRoomId]->Release();
					// Release the examine room
					ReleaseExamineRoom(examineRoomId);
					// Hand the sheet to cashier
					break;
				default:
					break;
			}
		}
		doTask();
	}
	totalNurseNum --;
}

// Doctor
void Doctor(int index) {
	initialLock->Acquire();
	startSign --;
	initialCV->Broadcast(initialLock);
	srand(time(0));
	
	while (1) {
		// Stay in the office waiting for nurse's signal
		// After receiving the signal from nurse, doctor start to interact with the patient
		// Get the patient's examination sheet
		doctorLock[index] -> Acquire();
		initialLock->Release();
		nurseDoctorLock->Acquire();
		doctorState[index] = AVAILABLE;
		nurseDoctorLock->Release();
		doctorCV[index] ->Wait(doctorLock[index]);
		if(test==7||test==6)
			printf("Doctor [%d] is leaving their office.\n", index);
		int roomNum = doctorGoRoomId[index];
		examineRoomPatientLock[roomNum] -> Acquire();
		// Wake up the patient
		SheetEntry *myLocalSheet = sheetForDoctor[index];
		doctorInRoom[roomNum] = index;
		examineRoomPatientCV[roomNum]->Signal(examineRoomPatientLock[roomNum]);
		examineRoomPatientLock[roomNum] -> Release();
		doctorCV[index]->Wait(doctorLock[index]);
		if (myLocalSheet->state == NEED_EXAMINE){
			// First time interact with the doctor
			// Start examination
			if (myLocalSheet->id < childNum){
				if(test==7||test==6)
					printf("Doctor [%d] is reading the examination sheet of Child Patient [%d] in Examination room [%d].\n", index, myLocalSheet->id, roomNum);
			}
			else{
				if(test==7||test==6)
					printf("Doctor [%d] is reading the examination sheet of Adult Patient [%d] in Examination room [%d].\n", index, myLocalSheet->id, roomNum);		  	
			}
			int result = rand()%4;
			switch (result) {
				case 0:
					// Take Xray
					myLocalSheet->state = NEED_XRAY;
					patientneedto[myLocalSheet->id] = NEED_XRAY;
					// Determin the number
					myLocalSheet->imageNum = 1+rand()%3;
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							printf("Doctor [%d] notes down in the sheet that Xray is needed for Child Patient [%d] in Examination room [%d].\n", index, myLocalSheet->id, roomNum);
					}
					else{
						if(test==7||test==6)
							printf("Doctor [%d] notes down in the sheet that Xray is needed for Adult Patient [%d] in Examination room [%d].\n", index, myLocalSheet->id, roomNum);				  	
					}
					
					
					//doctor ask patient to take xray and wait for the patient to come back
					break;
				case 1:
					// Take shot
					myLocalSheet->state = NEED_SHOT;
					patientneedto[myLocalSheet->id] = NEED_SHOT;
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							printf("Doctor [%d] notes down in the sheet that Child Patient [%d] needs to be given a shot in Examination room [%d].\n", index, myLocalSheet->id, roomNum);                                     
					}
					else{
						if(test==7||test==6)
							printf("Doctor [%d] notes down in the sheet that Adult Patient [%d] needs to be given a shot in Examination room [%d].\n", index, myLocalSheet->id, roomNum);                                     				  	
					}
					
					break;
					
				default:
					// Fine
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							printf("Doctor [%d] diagnoses Child Patient [%d] to be fine and is leaving the Examination room [%d].\n", index, myLocalSheet->id, roomNum);
					}
					else{
						if(test==7||test==6)
							printf("Doctor [%d] diagnoses Adult Patient [%d] to be fine and is leaving the Examination room [%d].\n", index, myLocalSheet->id, roomNum);				  	
					}
					myLocalSheet->state = FINE;                                      
			}
		}   
		else if (myLocalSheet->state == XRAY_DONE){ 
			int result = 0 + rand()%4;  	
			if(test==7||test==6)           
				printf("Doctor [%d] is examining the Xrays of [Adult/Child] Patient [%d] in Examination room [%d].\n", index, myLocalSheet->id, roomNum);
			switch (result) {
				case 0:
					//need shot after xray
					myLocalSheet->state = NEED_SHOT;
					patientneedto[myLocalSheet->id] = NEED_SHOT;
					if (myLocalSheet->id < childNum){
						if(test==7||test==6)
							printf("Doctor [%d] notes down in the sheet that Child Patient [%d] needs to be given a shot in Examination room [%d].\n", index, myLocalSheet->id, roomNum);                                     
					}
					else{
						if(test==7||test==6)
							printf("Doctor [%d] notes down in the sheet that Adult Patient [%d] needs to be given a shot in Examination room [%d].\n", index, myLocalSheet->id, roomNum);                                     				  	
					}
					break;
				default:	
					myLocalSheet->state = DONE;	
			}				
		}
		doctorCV[index]->Signal(doctorLock[index]);
		doctorCV[index]->Wait(doctorLock[index]);
		wallPocketLock -> Acquire();
		wallPocket[roomNum] = myLocalSheet;
		wallPocketLock -> Release();
		//doctorState[index] = AVAILABLE;
		if(test==7||test==6)
			printf("Doctor [%d] has left Examination Room [%d].\n", index, roomNum);
		doctorLock[index] -> Release();
		if(test==7||test==6)
			printf("Doctor [%d] is going to their office.\n", index);
	}
}

// Only one cashier
void Cashier(int index) {
	// Make sure the thread is executed before patient threads
	initialLock->Acquire();
	startSign --;
	initialCV->Broadcast(initialLock);
	
	// Work like the waiting room nurse
	while (1) {
		// Check the line
		cashierLineLock->Acquire();
		initialLock->Release();
		if (cashierLineNum == 0) {
			// If no patient wait in the line, sleep until patient comes
			cashierState = AVAILABLE;
		}else {
			// If there are patients in the line signal one patient
			cashierLineCV->Signal(cashierLineLock);
			cashierLineNum --;	// Decrease the number of patients in the line
			cashierState = UNAVAILABLE;
		}
		cashierLock->Acquire();
		cashierLineLock->Release();
		cashierCV->Wait(cashierLock);
		int patientId = patientIdWithCashier;
		if (patientId < childNum){
			if(test==7||test==3||test==1)
				printf("Cashier receives the examination sheet for Child Patient [%d] from Parent [%d].\n", patientId,patientId);
		}
		else{
			if(test==7||test==3)
				printf("Cashier receives the examination sheet from Adult Patient[%d].\n", patientId);	  	
		}
		// Wait patient to pay
		cashierCV->Signal(cashierLock);
		if (patientId < childNum){
			if(test==7||test==1||test==3)
				printf("Cashier reads the examination sheet of Child Patient [%d] and asks Parent [%d] to pay $....\n", patientId,patientId);
		}
		else{
			if(test==7||test==3)
				printf("Cashier reads the examination sheet of Adult Patient [%d] and asks him to pay $....\n", patientId);
		}
		cashierCV->Wait(cashierLock);
		if (patientId < childNum){
			if(test==7||test==3||test==1)
				printf("Cashier accepts $.... from Parent [%d].\n", patientId);
		}
		else{
			if(test==7||test==3)
				printf("Cashier accepts $.... from Adult Patient [%d].\n", patientId);			
		}
		// Wait for patient leaving
		cashierCV->Signal(cashierLock);
		if (patientId < childNum){
			if(test==7||test==3||test==1)
				printf("Cashier gives a receipt of $....... to Parent [%d].\n", patientId);
		}
		else{
			if(test==7||test==3)
				printf("Cashier gives a receipt of $..... to Adult Patient [%d].\n", patientId);
		}
		cashierCV->Wait(cashierLock);
		// loop
		if (totalPatientNum <= 0) {
			break;
		}
		cashierLock->Release();
	}
}

// XRay Technician
void XRayTechnician(int index) {
	// Make sure the thread is executed before patient threads
	initialLock->Acquire();
	startSign --;
	initialCV->Broadcast(initialLock);
	srand(time(0));
	while (1) {
		// Wait until a Nurse brings a Patient
		// Get the patient's exemination sheet
		xRayWaitLineLock[index]->Acquire();	
		initialLock->Release();
		SheetEntry *myLocalSheet;
		if (xRayWaitLineNum[index] == 0){
			//// If no patient wait in the line, sleep until patient comes
			xtechnicianstate[index] = AVAILABLE;
		}
		else{
			//If there are patients in the line signal one patient
			xRayWaitLineCV[index]->Signal(xRayWaitLineLock[index]);
			xRayWaitLineNum[index] --;      // Decrease the number of patients in the line
			xtechnicianstate[index] = UNAVAILABLE;
		}
		xRayLock[index]->Acquire();
		xRayWaitLineLock[index]->Release();
		xRayCV[index]->Wait(xRayLock[index]);
		waitListLock[index]->Acquire();
		myLocalSheet = (SheetEntry *)xrayWaitList[index]->Remove();
		waitListLock[index]->Release();
		int imageNum = myLocalSheet->imageNum;
		xtImageNum[index] = imageNum;
		// Wait for the patient getting onto the table
		// Take images
		// Stay in xray room waiting for nurse's signal
		// After receiving the signal from nurse, xray technician start to interact with the patient
		// Get the patient's examination sheet
		
		//Patient comes
		//technician take 3 images        
		if (myLocalSheet->id < childNum){
			if(test==7)
				printf("Xray technician [%d] asks Child Patient [%d] to get on the table.\n", index, myLocalSheet->id);
		}
		else{
			if(test==7)
				printf("Xray technician [%d] asks Adult Patient [%d] to get on the table.\n", index, myLocalSheet->id);	
		}
		xRayCV[index]->Signal(xRayLock[index]);
		xRayCV[index]->Wait(xRayLock[index]);
		for (int i=0;i < imageNum;i++){
			if (myLocalSheet->id < childNum){
				if(test==7)
					printf("Xray Technician [%d] takes an Xray Image of Child Patient [%d].\n", index, myLocalSheet->id);
			}
			else{
				if(test==7)
			  printf("Xray Technician [%d] takes an Xray Image of Adult Patient [%d].\n", index, myLocalSheet->id);				
			}
			int result = rand()%3;
			switch (result) {
				case 0:
					myLocalSheet->xrayResults[i] = NOTHING;
					if (myLocalSheet->id < childNum){
						if(test==7)
							printf("Xray Technician [%d] records nothing on Child Patient [%d] 's examination sheet.\n", index, myLocalSheet->id);
					}
					else{
						if(test==7)
							printf("Xray Technician [%d] records nothing on Adult Patient [%d] 's examination sheet.\n", index, myLocalSheet->id);						
					}
					break;
				case 1:
					myLocalSheet->xrayResults[i] = BREAK;
					if (myLocalSheet->id < childNum){
						if(test==7)
							printf("Xray Technician [%d] records break on Child Patient [%d] 's examination sheet.\n", index, myLocalSheet->id);
					}
					else{
						if(test==7)
							printf("Xray Technician [%d] records break on Adult Patient [%d] 's examination sheet.\n", index, myLocalSheet->id);						
					}					
					break;
				case 2:
					myLocalSheet->xrayResults[i] = COMPOUND_FRACTURE;
					if (myLocalSheet->id < childNum){
						if(test==7)
							printf("Xray Technician [%d] records compound fracture on Child Patient [%d] 's examination sheet.\n", index, myLocalSheet->id);
					}
					else{
						if(test==7)
							printf("Xray Technician [%d] records compound fracture on Adult Patient [%d] 's examination sheet.\n", index, myLocalSheet->id);						
					}							
					break;
			}
			//printf("xRay technician [%d] wrote image [%d] on patient [%d] sheet\n", index, i, myLocalSheet->id);  
			if (i+1 < imageNum) {
				if (myLocalSheet->id < childNum){
					if(test==7)
						printf("Xray Technician [%d] asks Child Patient [%d] to move.\n", index, myLocalSheet->id);
				}
				else{
					if(test==7)
						printf("Xray Technician [%d] asks Adult Patient [%d] to move.\n", index, myLocalSheet->id);					
				}
				xRayCV[index]->Signal(xRayLock[index]);
				xRayCV[index]->Wait(xRayLock[index]);
			}
		}
		myLocalSheet->state = XRAY_DONE;
		finishListLock->Acquire();
		xrayFinishList->Append(myLocalSheet);
		if (myLocalSheet->id < childNum){
			if(test==7||test==1){
				printf("X-ray Technician [%d] tells Parent [%d] to wait in Xray waiting room.\n",index, myLocalSheet->id);
				printf("X-ray Technician [%d] puts Parent [%d] in Xray waiting room wall pocket.\n",index, myLocalSheet->id);
			}
		}else{
			if(test==7){
				printf("X-ray Technician [%d] tells Adult Patient [%d] to wait in Xray waiting room.\n",index, myLocalSheet->id);
				printf("X-ray Technician [%d] puts Adult Patient [%d] in Xray waiting room wall pocket.\n",index, myLocalSheet->id);
			}
			
		}
		xRayCV[index]->Signal(xRayLock[index]);
		xRayCV[index]->Wait(xRayLock[index]);
		xRayLock[index]->Release();
		finishListLock->Release();
	}
}

// Test functions

// Clean up
void CleanUp(int patientNum) {
	printf("Now free the memory \n");
	
	delete initialLock;
	initialLock = NULL;
	delete initialCV;
	initialCV = NULL;
	
	delete wrnLock;
	wrnLock = NULL;
	delete wrnCV;
	wrnCV = NULL;
	delete wrnLineLock;
	wrnLineLock = NULL;
	delete wrnLineCV;
	wrnLineCV = NULL;
	delete wrnList;
	wrnList = NULL;
	
	delete cashierLock;
	cashierLock = NULL;
	delete cashierCV;
	cashierCV = NULL;
	delete cashierLineLock;
	cashierLineLock = NULL;
	delete cashierLineCV;
	cashierLineCV = NULL;
	
	delete cabinetLock;
	cabinetLock = NULL;
	delete nurseWrnLineCV;
	nurseWrnLineCV = NULL;
	delete nurseXtechLock;
	nurseXtechLock = NULL;
	delete nurseDoctorLock;
	nurseDoctorLock = NULL;
	
	delete wallPocketLock;
	wallPocketLock = NULL;
	for (int i=0; i<MAX_NUM_ROOMS; i++) {
		delete examineRoomPatientLock[i];
		examineRoomPatientLock[i] = NULL;
		delete examineRoomPatientCV[i];
		examineRoomPatientCV[i] = NULL;
	}

	delete finishListLock;
	finishListLock = NULL;
	delete xrayFinishList;
	xrayFinishList = NULL;
	for (int i=0; i<MAX_NUM_XTECH; i++) {
		delete xrayWaitList[i];
		xrayWaitList[i] = NULL;
		delete xRayLock[i];
		xRayLock[i] = NULL;
		delete xRayCV[i];
		xRayCV[i] = NULL;
		delete waitListLock[i];
		waitListLock[i] = NULL;
		delete xRayWaitLineLock[i];
		xRayWaitLineLock[i] = NULL;
		delete xRayWaitLineCV[i];
		xRayWaitLineCV[i] = NULL;
	}
	
	for (int i=0; i<patientNum+childNum; i++) {
		delete patientLock[i];
		patientLock[i] = NULL;
		delete patientCV[i];
		patientCV[i] = NULL;
	}
	delete [] patientLock;
	delete [] patientCV;
	delete [] roomId;
	delete [] xtIdWithPatient;
	delete [] patientneedto;
	delete [] symptomResponse;
	delete [] patientWithNurse;
	
	for (int i=0; i<childNum; i++) {
		delete childLock[i];
		childLock[i] = NULL;
		delete childCV[i];
		childCV[i] = NULL;
	}
	delete [] childLock;
	delete [] childCV;
	delete [] childAction;
	
	for (int i=0; i<MAX_NUM_DOCTORS; i++) {
		delete doctorLock[i];
		doctorLock[i] = NULL;
		delete doctorCV[i];
		doctorCV[i] = NULL;
	}
}

void Initialize(int patientNum, int xtechNum, int doctorNum, int examRoomNum) {
	startSign = 0;
	
	printf("Number of Doctors = [%d]\n", doctorNum);
	printf("Number of Nurses = [%d]\n", totalNurseNum);
	printf("Number of XRay Technicians = [%d]\n", xtechNum);
	printf("Number of Adult Patients = [%d]\n", patientNum);
	printf("Number of Parents/Child Patients = [%d]\n", childNum);
	printf("Number of Examination Rooms = [%d]\n", examRoomNum);
	// Initialize the global variables
	possibleSymptons[0] = PAIN;
	possibleSymptons[1] = NAUSEA;
	possibleSymptons[2] = ALIEN_VOICIES;
	
	possibleXrayResult[0] = NOTHING;
	possibleXrayResult[1] = BREAK;
	possibleXrayResult[2] = COMPOUND_FRACTURE;
	
	initialLock = new Lock("initialLock");
	initialCV = new Condition("initialCV");
	
	// Waiting room nurse
	wrnState = AVAILABLE;
	wrnLock = new Lock("wrnLock");
	wrnCV = new Condition("wrnCV");
	wrnLineLock = new Lock("wrnLineLock");
	wrnLineCV = new Condition("wrnLineCV");
	wrnList = new List;
	wrnLineNum = 0;
	
	// Cashier
	cashierState = AVAILABLE;
	cashierLock = new Lock("cashierLock");
	cashierCV = new Condition("cashierCV");
	cashierLineLock = new Lock("cashierLineLock");
	cashierLineCV = new Condition("cashierLineCV");
	cashierLineNum = 0;
	
	// Nurse
	cabinetLock = new Lock("cabinetLock");
	nurseWrnLineCV = new Condition("nurseWrnLineCV");
	nurseXtechLock = new Lock("nurseXtechLock");
	nurseDoctorLock = new Lock("nurseDoctorLock");
	nurseWrnCount = 0;
	patientWaitNum = 0;
	
	// Examine room
	wallPocketLock = new Lock("wallPocketLock");
	for (int i=0; i<MAX_NUM_ROOMS; i++) {
		if (i<totalNurseNum) {
			examineRoomPatientLock[i] = new Lock("examineRoomPatientLock");
			examineRoomPatientCV[i] = new Condition("examineRoomPatientCV");
			examineRoom[i] = NOT_USE;
		}else {
			examineRoom[i] = NOT_EXIST;
		}
	}
	
	// Xray Technician
	xRayTechNum = xtechNum;
	finishListLock = new Lock("finishListLock");
	xrayFinishList = new List;
	for (int i=0; i<MAX_NUM_XTECH; i++) {
		if (i < xtechNum) {
			xtechnicianstate[i] = AVAILABLE;
			xRayLock[i] = new Lock("xRayLock");
			xRayCV[i] = new Condition("xRayCV");
			waitListLock[i] = new Lock("waitListLock");
			xRayWaitLineLock[i] = new Lock("xRayWaitLineLock");
			xRayWaitLineCV[i] = new Condition("xRayWaitLineCV");
			xRayWaitLineNum[i] = 0;
			xrayWaitList[i] = new List;
		}else {
			xRayWaitLineNum[i] = 99999999;
			xtechnicianstate[i] = noExist;
		}
	}
	
	// Patient
	patientLock = new Lock* [patientNum+childNum];
	patientCV = new Condition* [patientNum+childNum];
	roomId = new int [patientNum+childNum];
	xtIdWithPatient = new int [patientNum+childNum];
	patientneedto = new PatientState [patientNum+childNum];
	symptomResponse = new Symptom [patientNum+childNum];
	patientWithNurse = new int [patientNum+childNum];
	
	totalPatientNum = patientNum+childNum;
	for (int i=0; i<patientNum+childNum; i++) {
		patientLock[i] = new Lock("patientLock");
		patientCV[i] = new Condition("patientCV");
		roomId[i] = -1;
		xtIdWithPatient[i] = -1;
		patientneedto[i] = NEED_EXAMINE;
		symptomResponse[i] = NAUSEA;
		patientWithNurse[i] = -1;
	}
	
	// Child
	childLock = new Lock* [childNum];
	childCV = new Condition* [childNum];
	childAction = new ChildAction[childNum];
	for (int i=0; i<childNum; i++) {
		childLock[i] = new Lock("childLock");
		childCV[i] = new Condition("childCV");
	}
	
	// Doctor
	for (int i=0; i<MAX_NUM_DOCTORS; i++) {
		if (i < doctorNum) {
			doctorState[i] = AVAILABLE;
			doctorLock[i] = new Lock("doctorLock");
			doctorCV[i] = new Condition("doctorCV");
		}else {
			doctorState[i] = noExist;
		}
	}
}

// main
void DoctorOffice() {
	totalNurseNum = 0;
	childNum = 0;
	int patientNum = 0;
	int examRoomNum = 0;
	int xtechNum = 0;
	int doctorNum = 0;
	
	int quit = 0;
	//while(!quit)
	//{
		printf("Test guideline:\n");
		printf("1. Child Patients are never abandoned by their Parent, nor go anywhere without their Parent.\n");
		printf("2. Waiting Room Nurses only talk to one Patient/Parent at a time. \n");
		printf("3. Cashiers only talk to one Patient/Parent at a time.\n");
		printf("4. Patients/Parents never go anywhere without being escorted by a Nurse.\n");
		printf("5. All Patients leave the Doctor's Office. No one stays in the Waiting Room, Examination Room, or Xray Room, forever.\n");
		printf("6. Two Doctors never examine the same Patient at the same time.\n");
		printf("7. Final Test. \n");
		printf("8. Quit. \n");
		printf("Please enter the number 1-8 corresponding to the above options:");
		char input;
		int flag;
		cin>>input;
		if(input=='1'){
			test = 1;
			totalNurseNum = 2;
			childNum = 3;
			patientNum = 0;
			examRoomNum = 2;
			xtechNum = 1;
			doctorNum = 2;
			
			Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
			
			startSign = totalNurseNum+2+doctorNum+xtechNum;
			// Fork the threads
			(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
			for (int i=0; i<xtechNum; i++) {
				(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
			}
			
			for (int i=0; i<totalNurseNum; i++) {
				(new Thread("Nurse"))->Fork(Nurse, i);
			}
			
			for (int i=0; i<doctorNum; i++) {
				(new Thread("Doctor"))->Fork(Doctor, i);
			}
			
			for (int i=0; i<patientNum+childNum; i++) {
				if (i<childNum) {
					(new Thread("Parent"))->Fork(Parent, i);
					(new Thread("Child"))->Fork(ChildPatient, i);
				}else {
					(new Thread("Patient"))->Fork(AdultPatient, i);
				}
			}
			Cashier(0);
			while (totalNurseNum > 0 || totalPatientNum > 0) {
				currentThread->Yield();
			}
			CleanUp(patientNum);
		}
		else if(input=='2'){
			test = 2;
			totalNurseNum = 2;
			childNum = 1;
			patientNum = 2;
			examRoomNum = 2;
			xtechNum = 1;
			doctorNum = 2;
			
			Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
			
			startSign = totalNurseNum+2+doctorNum+xtechNum;
			// Fork the threads
			(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
			for (int i=0; i<xtechNum; i++) {
				(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
			}
			
			for (int i=0; i<totalNurseNum; i++) {
				(new Thread("Nurse"))->Fork(Nurse, i);
			}
			
			for (int i=0; i<doctorNum; i++) {
				(new Thread("Doctor"))->Fork(Doctor, i);
			}
			
			for (int i=0; i<patientNum+childNum; i++) {
				if (i<childNum) {
					(new Thread("Parent"))->Fork(Parent, i);
					(new Thread("Child"))->Fork(ChildPatient, i);
				}else {
					(new Thread("Patient"))->Fork(AdultPatient, i);
				}
			}
			Cashier(0);
			while (totalNurseNum > 0 || totalPatientNum > 0) {
				currentThread->Yield();
			}
			CleanUp(patientNum);
		}
		else if(input=='3'){
			test = 3;
			totalNurseNum = 2;
			childNum = 1;
			patientNum = 2;
			examRoomNum = 2;
			xtechNum = 1;
			doctorNum = 2;
			
			Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
			
			startSign = totalNurseNum+2+doctorNum+xtechNum;
			// Fork the threads
			(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
			for (int i=0; i<xtechNum; i++) {
				(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
			}
			
			for (int i=0; i<totalNurseNum; i++) {
				(new Thread("Nurse"))->Fork(Nurse, i);
			}
			
			for (int i=0; i<doctorNum; i++) {
				(new Thread("Doctor"))->Fork(Doctor, i);
			}
			
			for (int i=0; i<patientNum+childNum; i++) {
				if (i<childNum) {
					(new Thread("Parent"))->Fork(Parent, i);
					(new Thread("Child"))->Fork(ChildPatient, i);
				}else {
					(new Thread("Patient"))->Fork(AdultPatient, i);
				}
			}
			Cashier(0);
			while (totalNurseNum > 0 || totalPatientNum > 0) {
				currentThread->Yield();
			}
			CleanUp(patientNum);
		}
		else if(input=='4'){
			test = 4;
			totalNurseNum = 2;
			childNum = 2;
			patientNum = 2;
			examRoomNum = 2;
			xtechNum = 1;
			doctorNum = 2;
			
			Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
			
			startSign = totalNurseNum+2+doctorNum+xtechNum;
			// Fork the threads
			(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
			for (int i=0; i<xtechNum; i++) {
				(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
			}
			
			for (int i=0; i<totalNurseNum; i++) {
				(new Thread("Nurse"))->Fork(Nurse, i);
			}
			
			for (int i=0; i<doctorNum; i++) {
				(new Thread("Doctor"))->Fork(Doctor, i);
			}
			
			for (int i=0; i<patientNum+childNum; i++) {
				if (i<childNum) {
					(new Thread("Parent"))->Fork(Parent, i);
					(new Thread("Child"))->Fork(ChildPatient, i);
				}else {
					(new Thread("Patient"))->Fork(AdultPatient, i);
				}
			}
			Cashier(0);
			while (totalNurseNum > 0 || totalPatientNum > 0) {
				currentThread->Yield();
			}
			CleanUp(patientNum);
		}
		else if(input=='5'){
			test = 5;
			totalNurseNum = 2;
			childNum = 1;
			patientNum = 2;
			examRoomNum = 2;
			xtechNum = 1;
			doctorNum = 2;
			
			Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
			
			startSign = totalNurseNum+2+doctorNum+xtechNum;
			// Fork the threads
			(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
			for (int i=0; i<xtechNum; i++) {
				(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
			}
			
			for (int i=0; i<totalNurseNum; i++) {
				(new Thread("Nurse"))->Fork(Nurse, i);
			}
			
			for (int i=0; i<doctorNum; i++) {
				(new Thread("Doctor"))->Fork(Doctor, i);
			}
			
			for (int i=0; i<patientNum+childNum; i++) {
				if (i<childNum) {
					(new Thread("Parent"))->Fork(Parent, i);
					(new Thread("Child"))->Fork(ChildPatient, i);
				}else {
					(new Thread("Patient"))->Fork(AdultPatient, i);
				}
			}
			Cashier(0);
			while (totalNurseNum > 0 || totalPatientNum > 0) {
				currentThread->Yield();
			}
			CleanUp(patientNum);
		}
		else if(input=='6'){
			test = 6;
			totalNurseNum = 2;
			childNum = 1;
			patientNum = 2;
			examRoomNum = 2;
			xtechNum = 1;
			doctorNum = 2;
			
			Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
			
			startSign = totalNurseNum+2+doctorNum+xtechNum;
			// Fork the threads
			(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
			for (int i=0; i<xtechNum; i++) {
				(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
			}
			
			for (int i=0; i<totalNurseNum; i++) {
				(new Thread("Nurse"))->Fork(Nurse, i);
			}
			
			for (int i=0; i<doctorNum; i++) {
				(new Thread("Doctor"))->Fork(Doctor, i);
			}
			
			for (int i=0; i<patientNum+childNum; i++) {
				if (i<childNum) {
					(new Thread("Parent"))->Fork(Parent, i);
					(new Thread("Child"))->Fork(ChildPatient, i);
				}else {
					(new Thread("Patient"))->Fork(AdultPatient, i);
				}
			}
			Cashier(0);
			while (totalNurseNum > 0 || totalPatientNum > 0) {
				currentThread->Yield();
			}
			CleanUp(patientNum);
		}
		else if(input=='7'){
			test = 7;
			printf("Enter the test data:\n");
			printf("Number of Doctors (2 to 3): = \n");
			cin>>doctorNum;
			if (doctorNum < 2 || doctorNum > 3){
				printf("The number of doctor must be 2 or 3!\n");
			}
			else{
				printf("Number of Nurses (2 - 5) = \n");
				cin>>totalNurseNum;
				if (totalNurseNum < 2 || totalNurseNum > 5){
					printf("The number of Nurse must between 2 and 5!\n");
				}
				else{
					printf("Number of XRay Technicians/Rooms (1 - 2) = \n");
					cin>>xtechNum;
					if (xtechNum < 1 || xtechNum >2){
						printf("The number of XRay Technicians must be 1 and 2!\n");
					}
					else{
						printf("Number of Parents/Child Patients (30 or more) = \n");
						cin>>childNum;
						if (childNum < 0){
							printf("The number of Child Patients must greater than 0!\n");
						}
						else{
							printf("Number of Adult Patients (30 or more) = \n");
							cin>>patientNum;
							if (patientNum < 0) {
								printf("The number of Adult Patients must greater than 0!\n");
							}else {
								printf("Number of Examination Rooms (2 - 5) = \n");
								cin>>examRoomNum;
								if (examRoomNum < 2 || examRoomNum > 5){
									printf("The number of Examination Rooms must between 2 and 5!\n");
								}else {
									//CleanUp(patientNum);
									Initialize(patientNum, xtechNum, doctorNum, examRoomNum);
									
									startSign = totalNurseNum+2+doctorNum+xtechNum;
									// Fork the threads
									(new Thread("WaitingRoomNurse"))->Fork(WaitingRoomNurse, 0);
									for (int i=0; i<xtechNum; i++) {
										(new Thread("Xray-Technician"))->Fork(XRayTechnician, i);
									}
									
									for (int i=0; i<totalNurseNum; i++) {
										(new Thread("Nurse"))->Fork(Nurse, i);
									}
									
									for (int i=0; i<doctorNum; i++) {
										(new Thread("Doctor"))->Fork(Doctor, i);
									}
									
									for (int i=0; i<patientNum+childNum; i++) {
										if (i<childNum) {
											(new Thread("Parent"))->Fork(Parent, i);
											(new Thread("Child"))->Fork(ChildPatient, i);
										}else {
											(new Thread("Patient"))->Fork(AdultPatient, i);
										}
									}
									Cashier(0);
									while (totalNurseNum > 0 || totalPatientNum > 0) {
										currentThread->Yield();
									}
									CleanUp(patientNum);
								}
							}
						}
					}
				}
			}
		}
		else if (input == '8'){
			quit = 1;;
		}
		else{
			printf("There is no option of your input.\n");
		}
	//}
}
#endif